import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/base/vehicle_data.dart';
import 'package:inmotion_protocol/common/compact.dart';
import 'package:inmotion_protocol/common/exceptions.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/lorin/bean/base/real_time_info.dart';
import 'package:inmotion_protocol/lorin/bean/common/response/response.dart';
import 'package:inmotion_protocol/lorin/bean/euc/e25/e25_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/euc_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/euc_statistics.dart';
import 'package:inmotion_protocol/lorin/bean/euc/p6/p6_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/euc/v18/v18_real_time_data.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/scooter_real_time_info.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/scooter_statistics.dart';
import 'package:inmotion_protocol/util/byte_util.dart';

class CommonVehicleRealTimeInfo extends AbsVehicleRealTimeInfo {
  Int16 busVoltage = Int16.zero; // 当前电池总电压
  Int16 busCurrent = Int16.zero; // 当前电池输出总电流
  Int16 chargeVoltage = Int16.zero; // 充电总电压
  Int16 chargeCurrent = Int16.zero; // 充电总电流
  Int16 speed = Int16.zero; // 当前速度
  Int16 acce = Int16.zero; // 行驶加速度
  Int16 torque = Int16.zero; // 电机输出扭矩
  Int16 outputRate = Int16.zero; // 输出矢量电压百分比
  Int16 batteryOutputPower = Int16.zero; // 电池输出功率
  Int16 motorOutputPower = Int16.zero; // 电机输出功率

  Uint16 batteryPercentage = Uint16.zero; // 剩余电量
  Uint16 batteryPercentageForRide = Uint16.zero; // 剩余可行驶的电量百分比
  Uint16 estimatedTotalMileage = Uint16.zero; // 预计满电可行驶里程
  Uint16 rtOverSpeedTiltBackThreshold = Uint16.zero; // 实时超速翘板阈值
  Uint16 rtOverSpeedWarningThreshold = Uint16.zero; // 实时超速报警阈值

  Int16 mosTemperature = Int16.zero; // 散热器(MOS管)温度
  Int16 motorTemperature = Int16.zero; // 电机温度
  Int16 boardTemperature = Int16.zero; // 主板高温区温度
  Uint8 lteSignal = Uint8.zero; // LTE信号强度

  Uint16 maxSpeed = Uint16.zero; // 最高速度
  Uint16 maxPower = Uint16.zero; // 最大总功率
  Uint16 maxMotorPower = Uint16.zero; // 最大电机输出功率

  Uint16 singleMileage = Uint16.zero; // 本次里程
  Uint32 singleConsumption = Uint32.zero; // 本次消耗能量
  Uint32 singleRecovery = Uint32.zero; // 本次回收能量
  Uint32 singleRideTime = Uint32.zero; // 本次骑行时间
  Uint32 singlePowerOnTime = Uint32.zero; // 本次开机时间

  Uint32 totalMileage = Uint32.zero; // 总里程
  Uint32 totalConsumption = Uint32.zero; // 总消耗能量
  Uint32 totalRecovery = Uint32.zero; // 总回收能量
  Uint32 totalRideTime = Uint32.zero; // 总骑行时间
  Uint32 totalPowerOnTime = Uint32.zero; // 总开机时间

  Uint16 tirePressure = Uint16.zero;

  CommonVehicleRealTimeInfo(ProductModel model, VersionWrapper version)
      : super(model, version);

  @override
  String toString() {
    return 'VehicleRealTimeInfo{busVoltage: $busVoltage, busCurrent: $busCurrent, chargeVoltage: $chargeVoltage, chargeCurrent: $chargeCurrent, speed: $speed, acce: $acce, torque: $torque, outputRate: $outputRate, batteryOutputPower: $batteryOutputPower, motorOutputPower: $motorOutputPower, batteryPercentage: $batteryPercentage, batteryPercentageForRide: $batteryPercentageForRide, estimatedTotalMileage: $estimatedTotalMileage, rtOverSpeedTiltBackThreshold: $rtOverSpeedTiltBackThreshold, rtOverSpeedWarningThreshold: $rtOverSpeedWarningThreshold, mosTemperature: $mosTemperature, motorTemperature: $motorTemperature, boardTemperature: $boardTemperature, lteSignal: $lteSignal, maxSpeed: $maxSpeed, maxPower: $maxPower, maxMotorPower: $maxMotorPower, singleMileage: $singleMileage, singleConsumption: $singleConsumption, singleRecovery: $singleRecovery, singleRideTime: $singleRideTime, singlePowerOnTime: $singlePowerOnTime, totalMileage: $totalMileage, totalConsumption: $totalConsumption, totalRecovery: $totalRecovery, totalRideTime: $totalRideTime, totalPowerOnTime: $totalPowerOnTime}';
  }

  @override
  void initCompact() {
    compact = _DefaultCommonVehicleRealTimeInfo();
  }

  RealTimeInfo getRealTimeInfo() {
    if(model.isV9Series()) {
      E25RealTimeInfo realTimeInfo = E25RealTimeInfo(model, version);
      realTimeInfo.voltage = busVoltage;
      realTimeInfo.current = busCurrent;
      realTimeInfo.speed = speed;
      realTimeInfo.torque = torque;
      realTimeInfo.outputRate = outputRate;
      realTimeInfo.batteryOutputPower = batteryOutputPower;
      realTimeInfo.motorOutputPower = motorOutputPower;
      realTimeInfo.batteryLevel = batteryPercentage;
      realTimeInfo.batteryLevelForRide = batteryPercentageForRide;
      realTimeInfo.estimatedTotalMileage = estimatedTotalMileage;
      realTimeInfo.remainderRange = Uint16(((batteryPercentageForRide.value / 10000) *
          estimatedTotalMileage.value)
          .toInt());
      realTimeInfo.overSpeedTiltBackThreshold = rtOverSpeedTiltBackThreshold;
      realTimeInfo.mileage = singleMileage;
      realTimeInfo.dynamicSpeedLimit = rtOverSpeedTiltBackThreshold;
      realTimeInfo.overSpeedWarningThreshold = rtOverSpeedWarningThreshold;
      realTimeInfo.mosTemp = mosTemperature;
      realTimeInfo.motorTemp = motorTemperature;
      realTimeInfo.boardTemp = boardTemperature;
      return realTimeInfo;
    }else if(model.isV12sSeries()){
      V18RealTimeInfo realTimeInfo = V18RealTimeInfo(model, version);
      realTimeInfo.voltage = busVoltage;
      realTimeInfo.current = busCurrent;
      realTimeInfo.speed = speed;
      realTimeInfo.torque = torque;
      realTimeInfo.outputRate = outputRate;
      realTimeInfo.batteryOutputPower = batteryOutputPower;
      realTimeInfo.motorOutputPower = motorOutputPower;
      realTimeInfo.batteryLevel = batteryPercentage;
      realTimeInfo.batteryLevelForRide = batteryPercentageForRide;
      realTimeInfo.estimatedTotalMileage = estimatedTotalMileage;
      realTimeInfo.remainderRange = Uint16(((batteryPercentageForRide.value / 10000) *
          estimatedTotalMileage.value)
          .toInt());
      realTimeInfo.overSpeedTiltBackThreshold = rtOverSpeedTiltBackThreshold;
      realTimeInfo.mileage = singleMileage;
      realTimeInfo.dynamicSpeedLimit = rtOverSpeedTiltBackThreshold;
      realTimeInfo.overSpeedWarningThreshold = rtOverSpeedWarningThreshold;
      realTimeInfo.mosTemp = mosTemperature;
      realTimeInfo.motorTemp = motorTemperature;
      realTimeInfo.boardTemp = boardTemperature;
      realTimeInfo.lteSingle = lteSignal;
      return realTimeInfo;
    } else if(model.isP6Series()){
      P6RealTimeInfo realTimeInfo = P6RealTimeInfo(model, version);
      realTimeInfo.voltage = busVoltage;
      realTimeInfo.current = busCurrent;
      realTimeInfo.speed = speed;
      realTimeInfo.torque = torque;
      realTimeInfo.outputRate = outputRate;
      realTimeInfo.batteryOutputPower = batteryOutputPower;
      realTimeInfo.motorOutputPower = motorOutputPower;
      realTimeInfo.batteryLevel = batteryPercentage;
      realTimeInfo.batteryLevelForRide = batteryPercentageForRide;
      realTimeInfo.estimatedTotalMileage = estimatedTotalMileage;
      realTimeInfo.remainderRange = Uint16(((batteryPercentageForRide.value / 10000) *
          estimatedTotalMileage.value)
          .toInt());
      realTimeInfo.overSpeedTiltBackThreshold = rtOverSpeedTiltBackThreshold;
      realTimeInfo.mileage = singleMileage;
      realTimeInfo.dynamicSpeedLimit = rtOverSpeedTiltBackThreshold;
      realTimeInfo.overSpeedWarningThreshold = rtOverSpeedWarningThreshold;
      realTimeInfo.mosTemp = mosTemperature;
      realTimeInfo.motorTemp = motorTemperature;
      realTimeInfo.boardTemp = boardTemperature;
      realTimeInfo.lteSingle = lteSignal;
      realTimeInfo.tirePressure = tirePressure;
      return realTimeInfo;
    }
    else{
      throw ProtocolParseException("Unsupported model: ${model.name}");
    }

  }

  HistoryStatistics getHistoryStatistics(CommonVehicleRealTimeInfo output, bool isEuc) {
    if(isEuc) {
      EucStatistics historyStatistics = EucStatistics(model, version);
      historyStatistics.maxSpeed = output.maxSpeed;
      historyStatistics.maxPower = output.maxPower;
      historyStatistics.maxMotorPower = output.maxMotorPower;
      historyStatistics.maxMosTemp = output.mosTemperature;
      historyStatistics.maxMotorTemp = output.motorTemperature;
      historyStatistics.maxBoardTemp = output.boardTemperature;
      historyStatistics.mileage = Uint32(output.singleMileage.value);
      historyStatistics.energy = output.singleConsumption;
      historyStatistics.recovery = output.singleRecovery;
      historyStatistics.rideTime = output.singleRideTime;
      historyStatistics.powerOnTime = output.singlePowerOnTime;
      return historyStatistics;
    } else {
      ScooterStatistics historyStatistics = ScooterStatistics(model, version);
      historyStatistics.maxSpeed = output.maxSpeed;
      historyStatistics.maxMosTemp = output.mosTemperature;
      historyStatistics.maxMotorTemp = output.motorTemperature;
      historyStatistics.mileage = Uint32(output.singleMileage.value);
      historyStatistics.energy = output.singleConsumption;
      historyStatistics.rideTime = output.singleRideTime;
      historyStatistics.powerOnTime = output.singlePowerOnTime;
      return historyStatistics;
    }
  }

  TotalStatistics getTotalStatistics(bool isEuc) {
    if(isEuc) {
      EucTotalStatistics totalStatistics = EucTotalStatistics(model, version);
      totalStatistics.mileage = totalMileage;
      totalStatistics.energy = totalConsumption;
      totalStatistics.recovery = totalRecovery;
      totalStatistics.rideTime = totalRideTime;
      totalStatistics.powerOnTime = totalPowerOnTime;
      return totalStatistics;
    } else {
      ScooterTotalStatistics totalStatistics = ScooterTotalStatistics(model, version);
      totalStatistics.mileage = totalMileage;
      totalStatistics.energy = totalConsumption;
      totalStatistics.powerOnTime = totalPowerOnTime;
      return totalStatistics;
    }
  }


}

class _DefaultCommonVehicleRealTimeInfo extends Compact<CommonVehicleRealTimeInfo> {
  @override
  void fromBytes(CommonVehicleRealTimeInfo output, Uint8ClampedList bytes, int offset) {
    if (bytes.length < offset + output.length()) {
      return;
    }
    int index = offset;

    output.busVoltage = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.busCurrent = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.chargeVoltage = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.chargeCurrent = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.speed = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.acce = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.torque = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.outputRate = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.batteryOutputPower = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.motorOutputPower = ByteUtil.bytes2Int16Le(bytes, index);
    index += 2;
    output.batteryPercentage = ByteUtil.bytes2Uint16Le(bytes, index);
    index += 2;
    output.batteryPercentageForRide = ByteUtil.bytes2Uint16Le(bytes, index);
    index += 2;
    output.estimatedTotalMileage = ByteUtil.bytes2Uint16Le(bytes, index);
    index += 2;
    output.rtOverSpeedTiltBackThreshold = ByteUtil.bytes2Uint16Le(bytes, index);
    index += 2;
    output.rtOverSpeedWarningThreshold = ByteUtil.bytes2Uint16Le(bytes, index);
    index += 2;
    output.mosTemperature = ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[index]) + 80);
    index += 1;
    output.motorTemperature = ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[index]) + 80);
    index += 1;
    output.boardTemperature = ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[index]) + 80);
    index += 1;
    output.lteSignal = ByteUtil.bytes2Uint8Le(bytes, index);
    index += 1;
    output.maxSpeed = ByteUtil.bytes2Uint16Le(bytes, index);
    index += 2;
    output.maxPower = ByteUtil.bytes2Uint16Le(bytes, index);
    index += 2;
    output.maxMotorPower = ByteUtil.bytes2Uint16Le(bytes, index);
    index += 2;
    output.singleMileage = ByteUtil.bytes2Uint16Le(bytes, index);
    index += 2;
    output.singleConsumption = ByteUtil.bytes2Uint32Le(bytes, index);
    index += 4;
    output.singleRecovery = ByteUtil.bytes2Uint32Le(bytes, index);
    index += 4;
    output.singleRideTime = ByteUtil.bytes2Uint32Le(bytes, index);
    index += 4;
    output.singlePowerOnTime = ByteUtil.bytes2Uint32Le(bytes, index);
    index += 4;
    output.totalMileage = ByteUtil.bytes2Uint32Le(bytes, index);
    index += 4;
    output.totalConsumption = ByteUtil.bytes2Uint32Le(bytes, index);
    index += 4;
    output.totalRecovery = ByteUtil.bytes2Uint32Le(bytes, index);
    index += 4;
    output.totalRideTime = ByteUtil.bytes2Uint32Le(bytes, index);
    index += 4;
    output.totalPowerOnTime = ByteUtil.bytes2Uint32Le(bytes, index);
    index += 4;
    output.tirePressure = ByteUtil.bytes2Uint16Le(bytes, index);
  }

  @override
  int length() {
    return 78;
  }
}
